
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ERROR(p)    while(expErr == 0) {expErrPos = p; printf("\n"
#define ERREND      ); expErr = 1; return 0.0;}

#define DEBUGM  //printf

int expErr = 0;
int expErrPos = 0;


double eval(char *exp);
double getExpr(char *exp, int *pos);
double getNumber(char *exp, int *pos);
int isNumberStart(char c);
double addTerms(char *exp, int *pos);
double multFactors(char *exp, int *pos);


int maina(void)
{
    char s[100];
    double x;
//    int n = 0;
    int i;

    while(1)
    {
        printf("> ");
        fgets(s, 99, stdin);
        s[strlen(s)-1] = 0;
        
        if (s[0] == 0)
        {
            printf(" -\n");
            continue;
        }

        if (strncmp(s, "exit", 5) == 0)
            break;

//        n = 0;
        x = eval(s);    
            
        if (!expErr)
            printf("ans: %g\n\n", x);
        else
        {
            printf("\n\t%s\n\t", s);
            for(i = 1; i < expErrPos; i++) putchar(' ');
            printf("^\n\n");
        }
    }    

    printf("\nBye!\n\n");    
    system("pause");
    exit(0);
}


double eval(char *exp)
{
    int n, k;
    double x;
    
    n = strlen(exp) - 1;
    k = 0;
    
    x = getExpr(exp, &k);
    
    DEBUGM(" K ended up as: %d\n", k);
    
    if (k <= n)
        ERROR(k+1)
            "Error: ending expected at position %d\n", k+1
        ERREND;
    
    return x;
}


double getExpr(char *exp, int *pos)
{
    expErr = 0;
    return addTerms(exp, pos);
}


double getNumber(char *exp, int *pos)
{
    int n = 0;
    double x = 0;

    DEBUGM("Enter get num. pos: %d\n", *pos);
    sscanf(exp+*pos, "%lg%n", &x, &n);
    
    *pos += n;
    DEBUGM("  num: %g. n: %d. pos: %d\n", x, n, *pos);
    return x;
}


int isNumberStart(char c)
{
    return (c >= '0' && c <= '9') || c == '-' || c == '+';
}



double addTerms(char *exp, int *pos)
{
    char c;
    double x = 0;
    
    DEBUGM("Enter addT. pos: %d\n", *pos);
    c = exp[*pos];
    
    if (c == '(' || isNumberStart(c))
    {
        x = multFactors(exp, pos);
    }
    else if (c == 0)
    {
        ERROR(*pos+1)
            "T Error: unexpected ending at position %d\n", *pos + 1
        ERREND;
    }
    else
    {
        ERROR(*pos+1)
            "Error: unexpected char '%c' at position %d\n", c, *pos + 1
        ERREND;
    }

    c = exp[*pos];

    if (c == '+')
    {   
        (*pos)++;
        return x + addTerms(exp, pos);
    }
    else if (c == '-')
    {   
        (*pos)++;
        return x - addTerms(exp, pos);
    }
    else if (c == 0 || c == ')')
    {
        return x;
    }
    else
    {
        ERROR(*pos+1)
            "Error: unexpected char '%c' at position %d\n", c, *pos + 1
        ERREND;
    }

}


double multFactors(char *exp, int *pos)
{
    char c;
    double x, temp;
    
    DEBUGM("Enter mulF. pos: %d\n", *pos);
    c = exp[*pos];
    DEBUGM("  mulf: inspected char\n");

    if (c == '(')
    {
        (*pos)++;
        x = getExpr(exp, pos);

        if (exp[*pos] != ')')
            ERROR(*pos+1)
                "Error: closing bracket missing at char %d\n", *pos + 1
            ERREND;
        
        (*pos)++;
    }
    else if (isNumberStart(c))
    {
        DEBUGM("  mulf: found num\n");
        x = getNumber(exp, pos);
    }
    else if (c == 0)
    {
        ERROR(*pos+1)
            "F Error: unexpected ending at position %d\n", *pos + 1
        ERREND;
    }
    else
    {
        (*pos)++;
        ERROR(*pos)
            "Error: unexpected char '%c' at position %d\n", c, *pos
        ERREND;
    }
    
    ////////////// Extension para exponentes ///////////////
    if (exp[*pos] == '^')
    {
        (*pos)++;
        
        if (exp[*pos] == '(')
        {
            (*pos)++;
            temp = getExpr(exp, pos);
            if (exp[*pos] != ')')
                ERROR(*pos+1)
                    "Error: closing bracket missing at char %d\n", *pos + 1
                ERREND;
            
            (*pos)++;
        }
        else if (isNumberStart(exp[*pos]))
        {
            temp = getNumber(exp, pos);
        }
        else
        {
            ERROR(*pos+1)
                "Error: unexpected char '%c' at position %d\n", 
                exp[*pos], *pos+1
            ERREND;
        }
        
        x = pow(x, temp);
    }
    /////////////////////////////////////////////
    

    if (exp[*pos] == '*')
    {   
        DEBUGM("  mulf: found * at pos: %d\n", *pos);
        (*pos)++;
        return x * multFactors(exp, pos);
    }
    else if (exp[*pos] == '/')
    {   
        DEBUGM("  mulf: found /\n");
        (*pos)++;
        return x / multFactors(exp, pos);
    }
    else
    {
        //(*pos)++;
        return x;
    }

}



